// 常用工具函数

/**
 * 防抖原理：一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
 * @param {*} fn 要执行的回调函数
 * @param {*} wait 延时的时间
 * @param {*} immediate 是否立即执行
 * @returns void
 * const myDebounce = debounce(data => {
 *  console.log(data)
 * })
 *
 * myDebounce('防抖传参')
 */
export const debounce = (fn, wait = 300, immediate = false) => {
  if (typeof fn !== 'function') throw new Error('fn 必须是一个函数！')
  let timer = null
  return function (...args) {
    const init = immediate && !timer
    clearTimeout(timer)
    timer = setTimeout(() => {
      timer = null
      !immediate && fn.call(this, ...args)
    }, wait)
    init && fn.call(this, ...args)
  }
}

/**
 * 废弃
 * 防抖原理：一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return void
 */
// let timeout = null;

// export const debounce = (func, wait = 500, immediate = false) => {
//   // 清除定时器
//   if (timeout !== null) clearTimeout(timeout);
//   // 立即执行，此类情况一般用不到
//   if (immediate) {
//     var callNow = !timeout;
//     timeout = setTimeout(function () {
//       timeout = null;
//     }, wait);
//     if (callNow) typeof func === 'function' && func();
//   } else {
//     // 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
//     timeout = setTimeout(function () {
//       typeof func === 'function' && func();
//     }, wait);
//   }
// }

/**
 * 倒计时
 * @param {Date} startTime - 开始时间 日期或时间戳
 * @param {Date} endTime - 结束时间日期或时间戳
 * @return {String}
 *
 * @example
 * timeDifference((new Date()).valueOf(), '2021/1/1 00:00:00')
 */
export const timeDifference = (startTime, endTime) => { // 可以传日期时间或时间戳
  const start = typeof (startTime) === 'number' ? startTime : new Date(startTime).getTime()
  const end = typeof (endTime) === 'number' ? endTime : new Date(endTime).getTime()
  const difference = end - start // 时间差的毫秒数
  const days = Math.floor(difference / (24 * 3600 * 1000)) // 计算出相差天数
  const leave1 = difference % (24 * 3600 * 1000) // 计算天数后剩余的毫秒数
  const hours = Math.floor(leave1 / (3600 * 1000)) // 计算相差分钟数
  const leave2 = leave1 % (3600 * 1000) // 计算小时数后剩余的毫秒数
  const minutes = Math.floor(leave2 / (60 * 1000)) // 计算相差秒数
  const leave3 = leave2 % (60 * 1000) // 计算分钟数后剩余的毫秒数
  const seconds = Math.round(leave3 / 1000)
  return `${days}天${hours}小时${minutes}分钟${seconds}秒`
}

/**
 * 来源await-to-js包
 * try ...catch的优雅处理方式
 * let [ err, user ] = await awaitTo(axios(123));
 * if(err) return cb('No user found');
 * @param { Promise } promise
 * @param { Object } errorExt - Additional Information you can pass to the err object
 * @return { Promise }
 */
export const awaitTo = (promise, errorExt = {}) => promise
  .then((data) => [null, data])
  .catch((err) => [Object.assign(err, errorExt), undefined])

/**
* 面向切片编程
var logic = function () {
console.log('业务代码')
}
// 切入
logic = AOP.before(logic, function () {
console.log('切入前代码')
})
logic = AOP.after(logic, function () {
console.log('切入后代码')
})

logic()
*/
export class AOP {
  /**
  * 切入前
  * @param {Function} fn         业务代码
  * @param {Function} beforeFn   前置函数
  * @returns
  */
  static before (fn, beforeFn) {
    return function () {
      beforeFn(...arguments)
      const agent = fn(...arguments)
      return agent
    }
  }

  /**
  * 切入后
  * @param {Function} fn         业务代码
  * @param {Function} afterFn   后置函数
  * @returns
  */
  static after (fn, afterFn) {
    return function () {
      const agent = fn(...arguments)
      afterFn(...arguments)
      return agent
    }
  }
}
